import JJRequestInfo from './JJRequestInfo'
import JJBaseRequest from './JJBaseRequest'
import {JJUtil, JJLog, JJCrypt} from './../util/index'
import { JJHttpHelper, JJError } from '../bizUtil/index.js';
import APPConfig from './../resource/file/appConfig/JJAPPConfig'
import {hexMD5} from './../thirdparty/index'
import JJAPPConfig from './../resource/file/appConfig/JJAPPConfig';

import {
    NativeModules
} from 'react-native'

const g_cacheIv = 'qwe123!@#'
const g_cryptKey = 'rty456$%^'

export default class JJRequest extends JJBaseRequest {

    serviceName = null
    userCacheDirectory = null

    identity = ''
    isEncryption = false
    isSaveToDisk = false
    parametersForSavedFileName = null
    sensitiveDataForSavedFileName = null

    constructor(identity, parameters, isEncryption, isSaveToDisk) {
        super()

        this.identity = identity;
        this.parameters = parameters;
        this.isEncryption = isEncryption;
        this.isSaveToDisk = isSaveToDisk;
        
        if (JJRequestInfo.isUserDidOnline && JJUtil.isNotNull(JJRequestInfo.userID)) {
            this.sensitiveDataForSavedFileName = JJRequestInfo.userID
        }
    }

    getHostUrl() {
        const host = JJHttpHelper.serverHostWithIdentity(this.identity)
        return host
    }

    getPathUrl() {
        const path = JJHttpHelper.serverPathWithIdentity(this.identity)
        return path
    }

    requestParameter() {
        let requestParameter = Object.assign(this.__getCommonParameter(), this.parameters)
        return requestParameter
    }

    postResponseNotification(isSuccess, value, error) {
        let info = { isSuccess, otherInfo: this.otherInfo, parameters: this.parameters }
        if (isSuccess) {
            info.value = value
        } else {
            info.error = error
        }

        // todo
        //WxNotificationCenter.postNotificationName(this.identity, info)
    }

    requestCompleteFilter(response) {
        response = this.processResponse(response)

        this.otherInfo.responseData = response
        
        if (this.successForBusiness(response) && this.isSaveToDisk) {
            const oldObject = this.obtainCache()
            let newObject = this.filterSuccessCallBackValue(true, response)
            newObject = this.operation(oldObject, newObject)

            this.saveObjectToCache(newObject);
        }

        this.processAbnormalStatus(response)

        return Promise.resolve(response);
    }

    processResponse(response) {
        // todo 处理业务，如解密等
        return response
    }

    processAbnormalStatus(response) {
        // todo 处理异常状态，如session超时等
        if ('9999' == response.code) { // session超时
            JJLog.log('!!!!! login session 超时 !!!!' + ' url: ' + this.buildRequestUrl())
            //JJLoginService.shareInstance().setIsUserDidOnline(false)
            //JJLoginService.shareInstance().setSessionKey(null)

            // todo
            //WxNotificationCenter.postNotificationName(JJLoginService.JJLoginServiceNotificationNameLoginSessionTimeout, response)
        }
    }

    successForBusiness(response) {
        // todo 判断应答是否业务成功
        const success = ('0000' == response.code);
        return success;
    }

    operation(oldObj, newObj) {
        return newObj
    }

    getCacheKey() {
        let keyStr = ''

        if (JJUtil.isNull(this.sensitiveDataForSavedFileName)) {
            keyStr = keyStr + '_'
        } else {
            keyStr = keyStr + this.sensitiveDataForSavedFileName + '_'
        }

        keyStr = keyStr + this.identity + '_'

        if (JJUtil.isNull(this.parametersForSavedFileName)) {
            keyStr = keyStr + JSON.stringify(this.parameters)
        } else {
            keyStr = keyStr + JSON.stringify(this.parametersForSavedFileName)
        }

        let value = hexMD5(keyStr)
        if (APPConfig.isDebug) {
            value = keyStr
        }
        
        return value ? value : keyStr
    }

    requestParameterForRN() {
        let options = {};

        if (JJUtil.isNotNull(this.serviceName)) {
            options['serviceName'] = this.serviceName;
        }

        if (JJUtil.isNotNull(this.userCacheDirectory)) {
            options['userCacheDirectory'] = this.userCacheDirectory;
        }

        if (JJUtil.isNotNull(this.identity)) {
            options['identity'] = this.identity;
        }

        if (JJUtil.isNotNull(this.methodType)) {
            options['methodType'] = this.methodType;
        }

        options['isEncryption'] = this.isEncryption;

        if (JJUtil.isNotNull(this.parameters)) {
            options['parameters'] = this.parameters;
        }

        options['isSaveToDisk'] = this.isSaveToDisk;

        if (JJUtil.isNotNull(this.otherInfo)) {
            options['otherInfo'] = this.otherInfo;
        }

        if (JJUtil.isNotNull(this.parametersForSavedFileName)) {
            options['parametersForSavedFileName'] = this.parametersForSavedFileName;
        }

        if (JJUtil.isNotNull(this.sensitiveDataForSavedFileName)) {
            options['sensitiveDataForSavedFileName'] = this.sensitiveDataForSavedFileName;
        }

        return JSON.stringify(options);
    }

    obtainCache() {
        if (JJAPPConfig.isAppParasitifer) {
            const options = this.requestParameterForRN();
            return new Promise((resolve) => {
                NativeModules.JJRNBridge.cache(options).then((result) => {
                    resolve(result);
                })
            });
        }

        return new Promise((resolve) => {
            const keyStr = this.getCacheKey()
            const value = localStorage.getItem(keyStr)
            if (JJUtil.isNull(value) || value.length <= 0) {
                resolve(null)
            }

            if (APPConfig.isDebug) {
                return resolve(value)
            }

            const cryptKey = g_cryptKey
            let decrypted = JJCrypt.aesDecrypt(value, cryptKey, g_cacheIv)
            try {
                const obj = JSON.parse(decrypted)
                return resolve(obj)
            } catch (error) {
                return resolve(decrypted)
            }
        })  
    }

    saveObjectToCache(obj) {
        if (JJUtil.isNull(obj)) {
            return
        }

        if (JJAPPConfig.isAppParasitifer) {
            const options = this.requestParameterForRN();
            if ('string' == typeof (obj)) {
                NativeModules.JJRNBridge.saveCache(options, obj);
            } else {
                NativeModules.JJRNBridge.saveCache(options, JSON.stringify(obj));
            }
            return
        }

        const keyStr = this.getCacheKey()
        const cryptKey = g_cryptKey

        const encrypted = JJCrypt.aesEncrypt(obj, cryptKey, g_cacheIv)
        
        if (APPConfig.isDebug) {
            localStorage.setItem(keyStr, obj)
        } else {
            localStorage.setItem(keyStr, encrypted)
        }
    }

    removeCache() {
        if (JJAPPConfig.isAppParasitifer) {
            const options = this.requestParameterForRN();
            NativeModules.JJRNBridge.removeCache(options);
            return
        }

        const keyStr = this.getCacheKey();
        localStorage.removeItem(keyStr);
    }

    __getCommonParameter() {
        // todo 通用参数
        let commonParam = {}
        return commonParam
    }

    toString() {
        const para = this.parameters
        let msg = '【Request】 url: ' + this.buildRequestUrl() + '; parameter: ' + JSON.stringify(para)
        return msg
    }
}
